<?php

namespace Gql\Core;

use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Container\Container;
use Illuminate\Http\Request;

class Context
{
    /**
     * 请求对象
     * @var Request
     */
    public $request;
    public $container;

    /**
     * 上一级返回的数据
     * @var null
     */
    public $preValue = null;

    /**
     * 请求参数
     * @var array
     */
    public $args = [];

    /**
     * 用于设置touken错误
     * @var null
     */
    public $tokenError = null;

    /**
     * ResolveInfo
     * @var ResolveInfo
     */
    public $info;
    /**
     * 是否标量
     * @var bool
     */
    public $isScalar = false;

    /**
     * 是否内省查询
     * @var bool
     */
    public $isIntrospection = false;

    /**
     * 公共的无需鉴权的
     * @var bool
     */
    public $isPublic = false;

    /**
     * 请求操作名称
     * @var string
     */
    public $operationName;

    /**
     * 请求字段名称
     * @var string
     */
    public $fieldName;
    /**
     * 请求的字段所属的类型名称
     * @var string
     */
    public $typeName;

    /**
     * 查询的字段，可以直接使用与数据的字段限定查询（非标量时有意义）
     * @var array
     */
    public $fields = [];

    /**
     * 请求的标量字段组（非标量时有意义）
     * @var array
     */
    public $selectFields = [];

    /**
     * 请求的非标量字段组（非标量时有意义）
     * @var array
     */
    public $selectOtherFields = [];

    /**
     * 请求的字段的所有标量字段组（非标量时有意义）
     * @var array
     */
    public $scalarFields = [];

    /**
     * 请求的字段的所有非标量字段组（非标量时有意义）
     * @var array
     */
    public $otherFields = [];

    /**
     * 关联组
     * @var array
     */
    public $withs = [];

    /**
     * 响应内容
     * @var null
     */
    public $body = null;

    public function __construct(Request $request, Container $container)
    {
        $this->request = $request;
        $this->container = $container;
    }

    public function init($preValue, $args, $context, ResolveInfo $info)
    {
        if (!$preValue instanceof PreValue) {
            $preValue = new PreValue($preValue);
        }
        if (!$args instanceof Args) {
            $args = new Args($args);
        }
        $this->setPreValue($preValue);
        $this->setArgs($args);
        $this->setInfo($info);
        return $this;
    }

    public function getFields($field=null)
    {
        $fields = $this->fields;
        if (is_array($field) || $field instanceof \ArrayAccess) {
            return array_merge($fields,$fields);
        }elseif(is_string($field)){
            array_push($fields,$field);
        }
        return $fields;
    }

    public function toArray(): array
    {
        $self = $this;
        return [
            $this->preValue,
            $this->args,
            $self,
            $this->info,
        ];
    }

    public function setPreValue(PreValue $preValue)
    {
        $this->preValue = $preValue;
    }

    public function setArgs(Args $args)
    {
        if (is_null($args)) $args = [];
        $this->args = $args;
    }

    public function setTokenError($error)
    {
        $this->tokenError = $error;
    }

    public function setInfo(ResolveInfo $info)
    {
        $isIntrospection = $info->parentType->config['isIntrospection'] ?? false;
        $this->setIsIntrospection($isIntrospection);
        $this->setOperationName($info->operation->operation);
        $this->info = $info;
    }

    public function setIsScalar(bool $isScalar)
    {
        $this->isScalar = $isScalar;
    }

    public function setIsIntrospection(bool $isIntrospection)
    {
        $this->isIntrospection = $isIntrospection;
    }

    public function setOperationName(string $operationName)
    {
        $this->operationName = $operationName;
    }

    public function setFieldName(string $fieldName)
    {
        $this->fieldName = $fieldName;
    }

    public function setTypeName(string $typeName)
    {
        $this->typeName = $typeName;
    }

    public function setFields(array $fields)
    {
        $this->fields = $fields;
    }

    public function setSelectFields(array $selectFields)
    {
        $this->selectFields = $selectFields;
    }

    public function setSelectOtherFields(array $selectOtherFields)
    {
        $this->selectOtherFields = $selectOtherFields;
    }

    public function setScalarFields(array $scalarFields)
    {
        $this->scalarFields = $scalarFields;
    }

    public function setOtherFields(array $otherFields)
    {
        $this->otherFields = $otherFields;
    }

    public function setWiths(array $withs)
    {
        $this->withs = array_filter($withs,function(With $with){
            return count($with->fields);
        });
    }

    public function pushWith(With $with)
    {
        array_push($this->withs, $with);
    }

    public function setBody($body)
    {
        $this->body = $body;
    }
}